/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.geoviewer.jxmap.panels;

import com.vividsolutions.jts.geom.Point;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JPanel;
import nl.cloudfarming.client.geoviewer.Category;
import nl.cloudfarming.client.geoviewer.Layer;
import nl.cloudfarming.client.geoviewer.LayerInfo;
import nl.cloudfarming.client.geoviewer.LayerObject;
import nl.cloudfarming.client.geoviewer.LayerObjectNode;
import nl.cloudfarming.client.geoviewer.LayerProvider;
import nl.cloudfarming.client.geoviewer.MapController;
import nl.cloudfarming.client.geoviewer.MapControllerLookup;
import nl.cloudfarming.client.geoviewer.Preset;
import org.jdesktop.swingx.JXMapViewer;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.openide.util.Lookup;
import org.openide.util.Lookup.Result;

/**
 *
 * @author Timon Veenstra
 */
public class RootMapPanelController implements MapController {

    private final RootMapPanel rootMapPanel = new RootMapPanel();
    private final Result<LayerProvider> providerResult = Lookup.getDefault().lookupResult(LayerProvider.class);
    private final Set<LayerProvider> providers = new HashSet<LayerProvider>();
    private final Map<Layer<LayerObject<?>>, LayerPanel> layerPanelMap = new HashMap<Layer<LayerObject<?>>, LayerPanel>();

    public RootMapPanelController() {

        initLayers();
        // registering provider change event
//        providerResult.addLookupListener(new LookupListener() {
//
//            @Override
//            public void resultChanged(LookupEvent ev) {
//                Result<LayerProvider> result = (Result<LayerProvider>) ev.getSource();
//                for (LayerProvider layerProvider : result.allInstances()) {
//                    if (!providers.contains(layerProvider)) {
//                        providers.add(layerProvider);
//                        layerProvider.getLookup().lookupResult(Layer.class).addLookupListener(new LayerLookupListener());
//                    }
//                }
//
//            }
//        });

        MapControllerLookup.addMapController(this);
    }

    private void initLayers() {
        for (LayerProvider provider : providerResult.allInstances()) {
            providers.add(provider);
            for (Layer layer : provider.getLookup().lookupAll(Layer.class)) {
                addLayer(layer);
            }
        }
    }

    public JPanel getPanel() {
        return this.rootMapPanel;
    }

    public void updateLayer(Layer<LayerObject<?>> layer) {
        if (!layerPanelMap.containsKey(layer)) {
            addLayer(layer);
        } else {
            rootMapPanel.removeLayerPanel(layerPanelMap.get(layer));
            addLayer(layer);
        }
    }

    @Override
    public void addLayer(final Layer<LayerObject<?>> layer) {
        layer.addPropertyChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (Layer.PROPERTY_PALETTE.equals(evt.getPropertyName())) {
                    layerPanelMap.get(layer).getView().repaint();
                }
            }
        });
        layer.addPropertyChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (Layer.PROPERTY_OBJECTS.equals(evt.getPropertyName())) {
                    List<LayerObject<?>> oldObjects = (List<LayerObject<?>>) evt.getOldValue();
                    List<LayerObject<?>> newObjects = (List<LayerObject<?>>) evt.getNewValue();
                    //
                    // remove old objects
                    //
                    List<LayerObject<?>> toBeRemovedObjects = new ArrayList<LayerObject<?>>();
                    for (LayerObject<?> lo : oldObjects) {
                        if (!newObjects.contains(lo)) {
                            toBeRemovedObjects.add(lo);

                        }
                    }
                    if (toBeRemovedObjects.size() > 0) {
                        layerPanelMap.get(layer).removeObjects(toBeRemovedObjects);
                        layerPanelMap.get(layer).getView().repaint();
                    }

                    //
                    // add new objects
                    List<LayerObject<?>> toBeAddedObjects = new ArrayList<LayerObject<?>>();
                    for (LayerObject<?> lo : newObjects) {
                        if (!oldObjects.contains(lo)) {
                            toBeAddedObjects.add(lo);

                        }
                    }
                    if (toBeAddedObjects.size() > 0) {
                        layerPanelMap.get(layer).addObjects(toBeAddedObjects);
                        layerPanelMap.get(layer).getView().repaint();
                    }
                }
            }
        });

        LayerPanel layerPanel = new LayerPanel(this, rootMapPanel, layer);

        layerPanel.addObjects(layer.getObjects());
        layerPanelMap.put(layer, layerPanel);
        rootMapPanel.addLayerPanel(layerPanel);
    }

    @Override
    public Set<Layer<LayerObject<?>>> getLayers() {
        return Collections.unmodifiableSet(layerPanelMap.keySet());
    }

    @Override
    public void setLayerOrder(int[] order, Category category) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public LayerInfo getLayerInfo(Layer layer) {
        assert layerPanelMap.containsKey(layer);
        return layerPanelMap.get(layer);
    }

    @Override
    public Preset getCurrentPreset() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String getMapName() {
        return "map:" + System.identityHashCode(this);
    }

    @Override
    public void selectObjectInLayer(Layer<LayerObject<?>> layer, LayerObjectNode layerObjectNode) {
        assert this.layerPanelMap.containsKey(layer);
        LayerPanel lp = this.layerPanelMap.get(layer);
        lp.setSelectedNode(layerObjectNode);


        Point centroid = layerObjectNode.getLayerObject().getGeometry().getCentroid();

        GeoPosition geoPosition = new GeoPosition(centroid.getY(), centroid.getX());


        rootMapPanel.getMapViewer().setCenterPosition(geoPosition);
        rootMapPanel.getMapViewer().setZoom(3);

    }

    JXMapViewer getViewer(){
        return rootMapPanel.getMapViewer();
    }

//    class LayerLookupListener implements LookupListener {
//
//        @Override
//        public void resultChanged(LookupEvent ev) {
//            Result<Layer> result = (Result<Layer>) ev.getSource();
//            for (Layer layer : result.allInstances()) {
//                if (!layers.containsKey(layer)) {
//                    addLayer(layer);
//                }
//            }
//        }
//    }
}
